/*
 * Copyright (C) 2021 HiHope Open Source Organization .
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 *
 * limitations under the License.
 */
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_device.h"

#include "lwip/netifapi.h"
#include "lwip/api_shell.h"

#include "ssd1306.h"

static void PrintLinkedInfo(WifiLinkedInfo* info)
{
    if (!info) return;

    static char macAddress[32] = {0};
    unsigned char* mac = info->bssid;
    snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    printf("bssid: %s, rssi: %d, connState: %d, reason: %d, ssid: %s\r\n",
        macAddress, info->rssi, info->connState, info->disconnectedReason, info->ssid);
}

static osThreadId_t g_StaTaskId = NULL;
static int g_StaExit = 0;

static struct netif* g_iface = NULL;
static int g_netId = -1;
static int g_connected = 0;
void DispayStaInfo(void)
{
    if (g_StaExit) {
        return;
    }

    ssd1306_Fill(Black);
    ssd1306_SetCursor(5, 5);
    ssd1306_DrawString("WIFI STA", Font_11x18, White);
    ssd1306_SetCursor(5, 5+18+5);
    if (g_connected) {
        ssd1306_DrawString("LINK...... OK", Font_7x10, White);
    } else {
        ssd1306_DrawString("LINK......", Font_7x10, White);
    }
    ssd1306_SetCursor(5, 5+18+5+10+5+10);
    ssd1306_DrawString("UP          DOWN", Font_7x10, White);
    ssd1306_UpdateScreen();
}

static void OnWifiConnectionChanged(int state, WifiLinkedInfo* info)
{
    if (!info) return;

    printf("%s %d, state = %d, info = \r\n", __FUNCTION__, __LINE__, state);
    PrintLinkedInfo(info);

    if (state == 1) {  // 3.1.4:WIFI_STATE_AVALIABLE, 3.2:WIFI_STATE_AVAILABLE
        if (g_connected == 0) {
            DispayStaInfo();
        }
        g_connected = 1;
    } else {
        if (g_connected == 1) {
            g_connected = 0;
            DispayStaInfo();
        }
    }
}

static void OnWifiScanStateChanged(int state, int size)
{
    printf("%s %d, state = %X, size = %d\r\n", __FUNCTION__, __LINE__, state, size);
}

static void WifiConnectTask(void)
{
    WifiErrorCode errCode;
    WifiEvent eventListener = {
        .OnWifiConnectionChanged = OnWifiConnectionChanged,
        .OnWifiScanStateChanged = OnWifiScanStateChanged
    };
    WifiDeviceConfig apConfig = {};

    osDelay(10);
    errCode = RegisterWifiEvent(&eventListener);
    printf("RegisterWifiEvent: ret=%d\r\n", errCode);

    // setup your AP params
    strcpy(apConfig.ssid, "DSX--STA");
    strcpy(apConfig.preSharedKey, "88888888");
    apConfig.securityType = WIFI_SEC_TYPE_PSK;

    DispayStaInfo();

    //while (1) {
        errCode = EnableWifi();
        printf("EnableWifi: ret=%d\r\n", errCode);
        osDelay(10);

        errCode = AddDeviceConfig(&apConfig, &g_netId);
        printf("AddDeviceConfig: ret=%d\r\n", errCode);

        g_connected = 0;
        errCode = ConnectTo(g_netId);
        printf("ConnectTo(%d): ret=%d\r\n", g_netId, errCode);

        while (!g_connected && !g_StaExit) {
            printf("[WifiConnectTask] trying to connect to %s\n", apConfig.ssid);
            osDelay(100);
        }
        printf("g_connected: %d\r\n", g_connected);
        osDelay(50);

        // 联网业务开始
        g_iface = netifapi_netif_find("wlan0");
        if (g_iface) {
            err_t ret = netifapi_dhcp_start(g_iface);
            printf("netifapi_dhcp_start: ret=%d\r\n", ret);

            osDelay(200); // wait DHCP server give me IP
            ret = netifapi_netif_common(g_iface, dhcp_clients_info_show, NULL);
            printf("netifapi_netif_common: ret=%d\r\n", ret);
        }

        DispayStaInfo();

        printf("connected to AP[%s] about 60s!\n", apConfig.ssid);
        // 模拟一段时间的联网业务
        int timeout = 60;
        while (timeout-- && !g_StaExit) {
            printf("[WifiConnectTask] after %d seconds,   I'll disconnect WiFi!\n", timeout);
            osDelay(100);
            if (!g_connected) {
                break;
            }
        }

        // 联网业务结束
        err_t ret = netifapi_dhcp_stop(g_iface);
        printf("netifapi_dhcp_stop: ret=%d\r\n", ret);

        Disconnect(); // disconnect with your AP
        RemoveDevice(g_netId); // remove AP config
        errCode = DisableWifi();
        printf("DisableWifi: ret=%d\r\n", errCode);
        g_iface = NULL;
        g_netId = -1;
        g_connected = 0;
        g_StaTaskId = NULL;
        g_StaExit = 0;
        //osDelay(200);
    //}
}

void WifiStaTestEntry(void)
{
    if (g_StaTaskId) {
        return;
    }

    //osPriorityAboveNormal[32], osPriorityNormal[24]
    //{.name, .attr_bits, .cb_mem, .cb_size, .stack_mem, .stack_size, .priority, .tz_module, .reserved}
    osThreadAttr_t attr = {"WifiConnectTask", 0, NULL, 0, NULL, 1024*8, 24, 0, 0};
    g_StaTaskId = osThreadNew((osThreadFunc_t)WifiConnectTask, NULL, &attr);
    if (g_StaTaskId == NULL) {
        printf("[WifiStaTestEntry] Falied to create %s!\n", attr.name);
    }
}
void WifiStaTestExit(void)
{
    g_StaExit = 1;
}
